package cn.xingzitech.common.id.snowflake;

import cn.xingzitech.common.id.IIdGenerator;
import cn.xingzitech.common.time.SystemClock;

public class SnowFlakeIdGenerator implements IIdGenerator<Long> {
    /**
     * 起止的时间戳：2025-05-10T 01:05:24.237Z 不可更改
     */
    private final static long START_TIME_STAMP=1746810324237L;
    /**
     * 序列号占用的位数
     */
    private final static long SEQUENCE_BIT = 12;

    /**
     * 机器标识占用的位数
     */
    private final static long MACHINE_BIT = 5;

    /**
     * 数据中心占用的位数
     */
    private final static long DATA_CENTER_BIT = 5;

    /**
     * 序列号最大值
     */
    private final static long MAX_SEQUENCE = ~(-1L << SEQUENCE_BIT);

    /**
     * 机器标识最大值
     */
    private final static long MAX_MACHINE_NUM = ~(-1L << MACHINE_BIT);

    /**
     * 数据中心最大值
     */
    private final static long MAX_DATA_CENTER_NUM = ~(-1L << DATA_CENTER_BIT);

    /**
     * 机器标识左移位数
     */
    private final static long MACHINE_LEFT = SEQUENCE_BIT;
    /**
     * 数据中心左移位数
     */
    private final static long DATACENTER_LEFT = SEQUENCE_BIT + MACHINE_BIT;
    /**
     * 时间戳左移位数
     */
    private final static long TIMESTAMP_LEFT= DATACENTER_LEFT + DATA_CENTER_BIT;
    /**
     * 数据中心
     */
    private final long datacenterId;
    /**
     * 机器标识
     */
    private final long machineId;
    /**
     * 序列号
     */
    private long sequence=0L;
    /**
     * 上一个时间戳
     */
    private long lastTimestamp = -1L;

    SnowFlakeIdGenerator(long datacenterId, long machineId) {
        if (datacenterId > MAX_DATA_CENTER_NUM || datacenterId < 0) {
            throw new IllegalArgumentException("datacenterId can't be greater than MAX_DATACENTER_NUM or less than 0");
        }
        if (machineId > MAX_MACHINE_NUM || machineId < 0) {
            throw new IllegalArgumentException("machineId can't be greater than MAX_MACHINE_NUM or less than 0");
        }
        this.datacenterId = datacenterId;
        this.machineId = machineId;
    }

    /**
     * 生成下一个id
     * @return Long
     */
    public synchronized Long nextId(){
        long currentTimestamp = getNewTimestamp();
        if (currentTimestamp < lastTimestamp){
            throw new RuntimeException("Clock moved backwards.  Refusing to generate id");
        }

        if (currentTimestamp == lastTimestamp){
            sequence = (sequence + 1) & MAX_SEQUENCE;
            if (sequence == 0){
                currentTimestamp=getNextMill();
            }
        }else{
            sequence = 0L;
        }
        lastTimestamp = currentTimestamp;
        return (currentTimestamp - START_TIME_STAMP)<<TIMESTAMP_LEFT
                | datacenterId << DATACENTER_LEFT
                | machineId << MACHINE_LEFT
                | sequence;
    }

    /**
     * 获取下一个毫秒值
     * @return long
     */
    private long getNextMill(){
        long mill = getNewTimestamp();
        while (mill <= lastTimestamp){
            mill = getNewTimestamp();
        }
        return mill;
    }

    /**
     * 获取当前时间戳
     * @return long
     */
    private long getNewTimestamp(){
        return SystemClock.millisClock().now();
    }

    /**
     * 获取雪花算法允许的最大的序列号值
     * @return long
     */
    public static long getMaxSequence() {
        return MAX_SEQUENCE;
    }

    /**
     * 获取雪花算法云熙的最大的机器标识
     * @return long
     */
    public static long getMaxMachineNum() {
        return MAX_MACHINE_NUM;
    }

    /**
     * 获取雪花算法允许的最大的数据中心id值
     * @return long
     */
    public static long getMaxDataCenterNum() {
        return MAX_DATA_CENTER_NUM;
    }
}
